package logger

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"path"
	"runtime"
	"strings"
	"time"

	"gitee.com/xixigroup/sweet-tools/base/interfaces"
	"github.com/sirupsen/logrus"
)

const (
	minimumCallerDepth = 5
	maximumCallerDepth = 15
)

var logging *logrus.Logger

type CustomFormatter struct {
	TimestampFormat string
}

func InitLogger(conf interfaces.LogConf) (*os.File, error) {
	logging = logrus.New()
	logging.Out = os.Stdout

	logFile := path.Join(conf.LogPath, time.Now().Format(conf.LogFileFormat))

	f, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err == nil {
		logging.Out = f
	} else {
		return nil, err
	}

	level, err := logrus.ParseLevel(conf.LogLevel)
	if err != nil {
		return nil, err
	}

	logging.SetReportCaller(false)

	logging.SetLevel(level)

	logging.SetFormatter(&CustomFormatter{
		TimestampFormat: "2006/01/02 15:04:05.000",
	})

	return f, nil
}

func (f *CustomFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	var b *bytes.Buffer
	if entry.Buffer != nil {
		b = entry.Buffer
	} else {
		b = &bytes.Buffer{}
	}

	timestamp := entry.Time.Format(f.TimestampFormat)
	level := strings.ToUpper(entry.Level.String())
	message := entry.Message
	//frame := entry.Caller

	file, line := findCaller()

	b.WriteString(fmt.Sprintf("%s|%s|%s%d|%v", timestamp, level, file, line, message))

	b.WriteByte('\n')
	return b.Bytes(), nil
}

func findCaller() (string, int) {
	file := ""
	line := 0
	// 遍历调用栈的最大索引为第11层.
	for i := minimumCallerDepth; i < maximumCallerDepth; i++ {
		file, line, _ = getCaller(i)
		// 过滤掉所有logrus包，即可得到生成代码信息
		if !strings.HasPrefix(file, "logrus") {
			break
		}
	}

	return file, line
}

func getCaller(skip int) (string, int, uintptr) {
	pc, file, line, ok := runtime.Caller(skip)
	if !ok {
		return "", 0, pc
	}
	n := 0

	// 获取包名
	for i := len(file) - 1; i > 0; i-- {
		if file[i] == '/' {
			n++
			if n >= 2 {
				file = file[i+1:]
				break
			}
		}
	}
	return file, line, pc
}

func SetOutput(f io.Writer) {
	if logging == nil {
		logging = logrus.New()
	}
	logging.Out = f
}

func SetLevel(logLevel string) {
	level, err := logrus.ParseLevel(logLevel)
	if err != nil {
		return
	}

	logging.SetLevel(level)
}

func Fatalf(format string, v ...interface{}) {
	logging.Fatalf(format, v...)
}

func Errorf(format string, v ...interface{}) {
	logging.Errorf(format, v...)
}

func Warnf(format string, v ...interface{}) {
	logging.Warnf(format, v...)
}

func Infof(format string, v ...interface{}) {
	logging.Infof(format, v...)
}

func Debugf(format string, v ...interface{}) {
	logging.Debugf(format, v...)
}

func Printf(format string, v ...interface{}) {
	logging.Debugf(format, v...)
}

func Fatal(v ...interface{}) {
	logging.Fatal(v...)
}

func Error(v ...interface{}) {
	logging.Error(v...)
}

func Warn(v ...interface{}) {
	logging.Warn(v...)
}

func Info(v ...interface{}) {
	logging.Info(v...)
}

func Debug(v ...interface{}) {
	logging.Debug(v...)
}

func Fatalln(v ...interface{}) {
	logging.Fatalln(v...)
}

func Errorln(v ...interface{}) {
	logging.Errorln(v...)
}

func Warnln(v ...interface{}) {
	logging.Warnln(v...)
}

func Infoln(v ...interface{}) {
	logging.Infoln(v...)
}

func Println(v ...interface{}) {
	logging.Debugln(v...)
}
